package com.up.habit.expand.swagger;

import com.alibaba.fastjson.JSON;
import com.beust.jcommander.internal.Maps;
import com.jfinal.config.Routes;
import com.jfinal.core.Controller;
import com.jfinal.kit.PropKit;
import com.jfinal.kit.StrKit;
import com.up.habit.Habit;
import com.up.habit.config.anno.ApiMethod;
import com.up.habit.config.anno.Ctr;
import com.up.habit.config.anno.Param;
import com.up.habit.config.anno.Params;
import com.up.habit.config.ConfigKit;
import com.up.habit.expand.swagger.bean.*;
import com.up.habit.kit.RequestKit;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;


/**
 * TODO:
 * <p>
 * @author 王剑洪 on 2019/10/23 17:55
 */
public class SwaggerKit {

    public static void addRoute(Routes routes) {
        if (PropKit.getBoolean("swagger.open", true)) {
            routes.add("/doc", SwaggerController.class);
        }
    }

    public static String getApiDoc(HttpServletRequest request, boolean isAdmin) {
        Swagger swagger;
        swagger = getSwagger(ConfigKit.getPackages(isAdmin ? ConfigKit.PACKAGE_ADMIN : ConfigKit.PACKAGE_API));
        swagger.setHost(RequestKit.getHost(request).replace("http://", "").replace("https://", ""));
        swagger.setBasePath("/");
        String json = JSON.toJSONString(swagger);
        json = json.replaceAll("\"defaultValue\"", "\"default\"");
        return json;

    }


    private static Swagger getSwagger(String packageName) {
        Swagger swagger = new Swagger();
        Info info = new Info(get("description"), get("version"), get("title"), get("termsOfService"));

        Contact contact = new Contact();
        contact.setName(get("contactName"));
        contact.setEmail(get("contactEmail"));
        contact.setUrl(get("contactUrl"));
        info.setContact(contact);

        License license = new License();
        license.setName(get("licenseName"));
        license.setUrl(get("licenseUrl"));

        info.setLicense(license);

        swagger.setInfo(info);

        Set<Class<?>> classes = ConfigKit.getClazz(packageName);
        List<String> withoutCtr = ConfigKit.getWithout();
        Map<String, Path> paths = new HashMap<>();
        if (classes != null && !classes.isEmpty()) {
            Map<String, String> classMap = Maps.newHashMap();
            for (Class<?> clazz : classes) {
                Ctr ctrl = clazz.getAnnotation(Ctr.class);
                //类不是继承Controller则不算控制器,没有控制器注解,过滤,
                if (!Controller.class.isAssignableFrom(clazz) || ctrl == null) {
                    continue;
                }
                //不需要加入路由的包名或类,过滤掉
                if (withoutCtr.contains(clazz.getPackage().getName()) || withoutCtr.contains(clazz.getName())) {
                    continue;
                }
                String ctrlMapping = ctrl.value();
                if (StrKit.isBlank(ctrlMapping)) {
                    ctrlMapping = clazz.getSimpleName().replace("Controller", "").replace("Ctrl", "");
                    ctrlMapping = StrKit.firstCharToLowerCase(ctrlMapping);

                }
                swagger.addTag(new Tag(ctrl.name(), ctrl.des()));
                Method[] methods = clazz.getMethods();
                for (Method method : methods) {
                    ApiMethod api = method.getAnnotation(ApiMethod.class);
                    if (api == null) {
                        continue;
                    }
                    String methodMapping = StrKit.isBlank(api.path()) ? method.getName() : api.path();
                    Path path = new Path();
                    String action = "/" + ctrlMapping + "/" + methodMapping;
                    Operation operation = new Operation(api.value(), ctrl.des(), ctrlMapping + methodMapping);
                    operation.addConsume("application/x-www-form-urlencoded");
                    operation.addTag(ctrl.name());
                    operation.addProduce("application/json");
                    //参数
                    Params params = method.getAnnotation(Params.class);
                    if (params != null) {
                        Param[] paramArray = params.value();
                        if (paramArray.length > 0) {
                            for (int i = 0; i < paramArray.length; i++) {
                                operation.addParameter(new Parameter(paramArray[i].name(), paramArray[i].des(), paramArray[i].dataType(), paramArray[i].required(), paramArray[i].format(), paramArray[i].defaultValue()));
                            }
                        }
                    }
                    operation.addResponse("data", new Response(api.response()));
                    path.setPost(operation);
                    swagger.addPath(action, path);
                }
            }

        }
        return swagger;
    }


    public static String get(String name) {
        return PropKit.get("swagger." + name);

    }


}
